package com.plugin.sproutcore.ui.wizards;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWizard;

import com.plugin.sproutcore.Activator;
import com.plugin.sproutcore.core.resources.natures.SproutCoreNature;
import com.plugin.sproutcore.lang.SproutCoreProcess;
import com.plugin.sproutcore.util.ConsoleUtil;

/**
 * This is a sample new wizard. Its role is to create a new file 
 * resource in the provided container. If the container resource
 * (a folder or a project) is selected in the workspace 
 * when the wizard is opened, it will accept it as the target
 * container. The wizard creates one file with the extension
 * "mpe". If a sample multi-page editor (also available
 * as a template) is registered for the same extension, it will
 * be able to open it.
 */

public class SproutCoreProjectWizard extends Wizard implements INewWizard {
	private SproutCoreProjectWizardPage page;
	private ISelection selection;
	
	/**
	 * Constructor for SproutCoreNewWizard.
	 */
	public SproutCoreProjectWizard() {
		super();
		setNeedsProgressMonitor(true);
	}
	
	/**
	 * Adding the page to the wizard.
	 */

	public void addPages() {
		page = new SproutCoreProjectWizardPage(selection);
		addPage(page);
	}

	/**
	 * This method is called when 'Finish' button is pressed in
	 * the wizard. We will create an operation and run it
	 * using wizard as execution context.
	 */
	public boolean performFinish() 
	{
		final String projectName = page.getProjectName();
		final String appName     = page.getApplicationName();
		IRunnableWithProgress op = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor) throws InvocationTargetException {
				try {
					doFinish(projectName, appName, monitor);
				} catch (CoreException e) {
					IProject project = getProject(projectName);
					if (project.exists()) {
						try {
							project.delete(true, monitor);
						} catch (CoreException ex) {}
					}
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};
		try {
			getContainer().run(true, false, op);
		} catch (InterruptedException e) {
			return false;
		} catch (InvocationTargetException e) {
			Throwable realException = e.getTargetException();
			MessageDialog.openError(getShell(), "Error", realException.getMessage());
			return false;
		}
		return true;
	}
	
	/**
	 * The worker method. It will find the container, create the
	 * file if missing or just replace its contents, and open
	 * the editor on the newly created file.
	 */

	private IProject getProject(String projectName)
	{
		return ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
	}

	private void doFinish( String projectName, String appName, IProgressMonitor monitor)
	throws CoreException 
	{
		// create a sample file
		monitor.beginTask("Creating " + projectName, 10);
		
		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
		
		if (!project.exists()) 
		{
			IProjectDescription desc= project.getWorkspace().newProjectDescription(project.getName());
			project.create(desc, monitor);
			monitor.worked(1);
		}
		else
		{
			throwCoreException("Project \"" + projectName + "\" already exists.");
		}

		if (!project.isOpen()) 
		{
			// run the sc-init application to create the sproutcore project
			try 
			{
				List<String> command = new ArrayList<String>();
				command.add("sc-gen");
				command.add("project");
				command.add(projectName);
				command.add(projectName);
				
				File workspace = project.getWorkspace().getRoot().getLocation().toFile();
				
				runSproutCoreBuildProcess(workspace, command, monitor);
				monitor.worked(1);

				// TODO Add validation for apps. They are not allowed to have 
				// spaces in them!
				command.clear();
				command.add("sc-gen");
				command.add("app");
				command.add(appName);
				command.add("--target="+appName);
				
				File projectFile = project.getLocation().toFile();
				
				runSproutCoreBuildProcess(projectFile, command, monitor);
				monitor.worked(1);
				
				project.open(monitor);
				
				addNature(project);
				
			} 
			catch (Exception e) {
				throwCoreException(e.getMessage());
			}
		}
	}
	
	private static void addNature(IProject project) throws CoreException
	{
		if (!project.hasNature(SproutCoreNature.NATURE_ID))
		{
			IProjectDescription description = project.getDescription();
			String[] prevNatures = description.getNatureIds();
			String[] newNatures = new String[prevNatures.length + 1];
			System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
			newNatures[prevNatures.length] = SproutCoreNature.NATURE_ID;
			description.setNatureIds(newNatures);
			project.setDescription(description, null);
		}
	}
	
	private void runSproutCoreBuildProcess(File dir, List<String> command, IProgressMonitor monitor)
	throws IOException, InterruptedException, CoreException
	{
		SproutCoreProcess.execute(command, dir, monitor);
	}

	
	public static void throwCoreException(String message) throws CoreException {
		IStatus status =
			new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.OK, message, null);
		throw new CoreException(status);
	}

	/**
	 * We will accept the selection in the workbench to see if
	 * we can initialize from it.
	 * @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
	 */
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.selection = selection;
		IWorkbenchWindow win = workbench.getActiveWorkbenchWindow();
		IWorkbenchPage page = win.getActivePage();
		ConsoleUtil.displayConsole(page);
	}
}